package com.loongtech.core.util;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.alibaba.fastjson.serializer.SerializerFeature;
import org.apache.commons.lang3.StringUtils;
import org.apache.commons.lang3.builder.EqualsBuilder;
import org.apache.commons.lang3.math.NumberUtils;
import org.apache.commons.lang3.reflect.ConstructorUtils;
import org.apache.commons.lang3.reflect.FieldUtils;
import org.apache.commons.lang3.reflect.MethodUtils;
import org.apache.http.HttpEntity;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.ClientProtocolException;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.CloseableHttpResponse;
import org.apache.http.client.methods.HttpGet;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClientBuilder;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.message.BasicHeader;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.protocol.HTTP;
import org.apache.http.util.EntityUtils;
import org.apache.logging.log4j.message.ParameterizedMessage;
import org.apache.poi.openxml4j.exceptions.InvalidFormatException;
import org.json.JSONException;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.*;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.net.URLEncoder;
import java.security.MessageDigest;
import java.util.*;
import java.util.Map.Entry;
import java.util.regex.Matcher;
import java.util.regex.Pattern;

public class Utils {
    /**
     * 为了效率特殊实现一个基于char进行分割的函数
     * @param line
     * @param sep
     * @return
     */
    public static List<String> splitString(String line, char sep) {
        if (null == line) {
            return new ArrayList<String>();
        }
        List<String> ret = new ArrayList<String>();
        int position = -1;
        for (int index = 0, size = line.length(); index < size; ++index) {
            if (line.charAt(index) == sep) {
                ret.add(line.substring(position + 1, index));
                position = index;
            }
        }
        ret.add(line.substring(position + 1));
        return ret;
    }


    /**
	 * 对接收到的request.getParamterMap过滤参数，去除空值字符串
	 * 
	 * @return
	 */
	public static Map<String, String> formatNullAndEmptyMap(Map<String, String[]> requestParams) {
		// 过滤参数，去除空值
		Map<String, String> retMap = new HashMap<String, String>();
		for (Map.Entry<String, String[]> entry : requestParams.entrySet()) {
			String[] values = entry.getValue();
			if (values == null || values.length == 0) {
				continue;
			}
			StringBuilder sb = new StringBuilder("");
			for (String str : values) {
				if (null != str) {
					sb.append(str).append(",");
				}
			}
			if (sb.length() > 0) {
				sb.deleteCharAt(sb.length() - 1);
			}
			retMap.put(entry.getKey(), sb.toString());
		}
		return retMap;
	}

	/**
	 * 对接收到的map过滤参数，去除空值字符串
	 * 
	 * @param params
	 * @return
	 */
	public static Map<String, Object> formatMapNullAndEmpty(Map<String, Object> params) {
		// 过滤参数，去除空值
		for (Iterator<Entry<String, Object>> it = params.entrySet().iterator(); it.hasNext();) {
			Object value = it.next().getValue();
			if (value == null || StringUtils.isBlank(value.toString())) {
				it.remove();
			}
		}
		return params;
	}

	/**
	 * 把数组所有元素排序，并按照“参数=参数值”的模式用“&”字符拼接成字符串
	 * 
	 * @param params
	 *            需要排序并参与字符拼接的参数组
	 * @return 拼接后字符串
	 */
	public static String createLinkString(Map<String, String> params) {
		List<String> keys = new ArrayList<String>(params.keySet());
		// 对key执行排序
		Collections.sort(keys);
		StringBuilder sb = new StringBuilder("");
		for (int i = 0, size = keys.size(); i < size; i++) {
			String key = keys.get(i);
			String value = params.get(key);
			if (i == size - 1) {
				sb.append(key).append("=").append(value);
			} else {
				sb.append(key).append("=").append(value).append("&");
			}
		}
		return sb.toString();
	}

	/**
	 * 对params中的参数，过滤掉strings和value为null or "" 按照key的字符顺序，用sep连接起来返回
	 * 
	 * @param params
	 * @param sep
	 * @param strings
	 * @return
	 */
	public static String linkValueString(Map<String, Object> params, String sep, String... strings) {
		StringBuilder sb = new StringBuilder();
		// 判断参数
		if (params == null || params.isEmpty()) {
			return sb.toString();
		}

		// 过滤字符集
		List<String> keyList = new ArrayList<String>(params.keySet());
		// 对key执行排序
		Collections.sort(keyList);
		Set<String> ignoreSet = getArraySet(strings);
		for (String key : keyList) {
			Object value = params.get(key);
			if (null == value || "".equals(value) || ignoreSet.contains(key.toLowerCase())) {
				continue;
			}
			sb.append(value).append(sep);
		}

		// 处理最后一个sep
		if (sb.length() > 0) {
			sb.delete(sb.lastIndexOf(sep), sb.length());
		}
		return sb.toString();
	}

	/**
	 * 除去数组中的空值和签名参数
	 * 
	 * @param paramMap
	 *            签名参数组
	 * @param strings
	 *            需要过滤的key数组
	 * @return 去掉空值与签名参数后的新签名参数Map
	 */
	public static Map<String, String> paramFilter(Map<String, String> paramMap, String... strings) {
		Map<String, String> result = new HashMap<String, String>();
		if (paramMap == null || paramMap.size() <= 0) {
			return result;
		}

		Set<String> ignoreSet = getArraySet(strings);
		for (Map.Entry<String, String> entry : paramMap.entrySet()) {
			String value = entry.getValue();
			if (null == value || "".equals(value) || ignoreSet.contains(entry.getKey().toLowerCase())) {
				continue;
			}
			result.put(entry.getKey(), value);
		}
		return result;
	}

	/**
	 * 将字符串数值转换为set
	 * 
	 * @param strings
	 * @return
	 */
	private static Set<String> getArraySet(String... strings) {
		Set<String> set = new HashSet<String>();
		if (null != strings) {
			for (String str : strings) {
				if (null != str) {
					set.add(str.toLowerCase());
				}
			}
		}
		return set;
	}

	/**
	 * MD5加密
	 * 
	 * @param s
	 *            被加密的字符串
	 * @return 加密后的字符串
	 */
	public static String md5(String s) {
		if (s == null)
			s = "";
		try {
			MessageDigest mdTemp = MessageDigest.getInstance("MD5");
			mdTemp.update(s.getBytes("UTF-8"));
			return new String(Hex.encodeHex(mdTemp.digest()));
		} catch (Exception e) {
			throw new RuntimeException(e);
		}
	}

	/**
	 * Base64编码
	 * 
	 * @param data
	 * @return
	 * @author HivenYang
	 * @date 2014年8月8日
	 */
	public static String base64Encode(byte[] data) {
		return Base64.encode(data);
	}

	/**
	 * Base64解码
	 * 
	 * @param encodeStr
	 * @return
	 * @author HivenYang
	 * @date 2014年8月8日
	 */
	public static byte[] base64Decode(String encodeStr) {
		return Base64.decode(encodeStr);
	}

	/**
	 * RSA公钥分块解码Base64编码字符串，默认密钥长度为1024
	 * 
	 * @param cipherBase64Str
	 * @param publicKey
	 * @return
	 * @throws Exception
	 * @author HivenYang
	 * @date 2014年8月8日
	 */
	public static String RSADecryptBlockByPublickey(String cipherBase64Str, String publicKey) throws Exception {
		RSAEncrypt rsaEncrypt = new RSAEncrypt();
		rsaEncrypt.loadPublicKey(publicKey);

		byte[] cipherData = base64Decode(cipherBase64Str);
		byte[] plainData = rsaEncrypt.decryptBlockByPublicKey(cipherData);
		String plainStr = new String(plainData, "UTF-8");

		return plainStr;
	}

	/**
	 * RSA公钥分块加密字符串成Base64编码的字符串，默认密钥长度为1024
	 * 
	 * @param plainStr
	 * @param publicKey
	 * @return
	 * @throws Exception
	 * @author HivenYang
	 * @date 2014年8月8日
	 */
	public static String RSAEncryptBlockByPublicKey(String plainStr, String publicKey) throws Exception {
		RSAEncrypt rsaEncrypt = new RSAEncrypt();
		rsaEncrypt.loadPublicKey(publicKey);

		byte[] cipherData = rsaEncrypt.encryptBlockByPublicKey(plainStr.getBytes());
		return base64Encode(cipherData);
	}

	/**
	 * RSA私钥分块加密字符串成Base64编码的字符串，默认密钥长度为1024
	 * 
	 * @param plainStr
	 * @return
	 * @throws Exception
	 * @author HivenYang
	 * @date 2014年8月8日
	 */
	public static String RSAEncryptBlockByPrivateKey(String plainStr, String privateKey) throws Exception {
		RSAEncrypt rsaEncrypt = new RSAEncrypt();
		rsaEncrypt.loadPrivateKey(privateKey);
		byte[] cipherData = rsaEncrypt.encryptBlockByPrivateKey(plainStr.getBytes());
		return base64Encode(cipherData);
	}

	/**
	 * RSA公钥解码Base64编码字符串
	 * 
	 * @param cipherBase64Str
	 * @param publicKey
	 * @return
	 * @throws Exception
	 * @author HivenYang
	 * @date 2014年8月8日
	 */
	public static String RSADecryptByPublickey(String cipherBase64Str, String publicKey) throws Exception {
		RSAEncrypt rsaEncrypt = new RSAEncrypt();
		rsaEncrypt.loadPublicKey(publicKey);

		byte[] cipherData = Base64.decode(cipherBase64Str);
		byte[] plainData = rsaEncrypt.decryptByPublicKey(cipherData);
		String plainStr = new String(plainData, "UTF-8");

		return plainStr;
	}

	/**
	 * 判断两个对象是否相等
	 * 
	 * @param objA
	 * @param objB
	 * @return
	 */
	public static boolean isEquals(Object objA, Object objB) {
		return new EqualsBuilder().append(objA, objB).isEquals();
	}

	/**
	 * 参数1是否为参数2的子类或接口实现
	 * 
	 * @param baseClazz
	 * @return
	 */
	public static boolean isInstanceof(Class<?> clazz, Class<?> baseClazz) {
		return baseClazz.isAssignableFrom(clazz);
	}

	/**
	 * 获得类泛型第一个参数的Class
	 * 
	 * @param clazz
	 * @return
	 */
	public static <T> Class<T> getSuperClassGenricType(Class<?> clazz) {
		return getSuperClassGenricType(clazz, 0);
	}

	/**
	 * 获得类泛型参数的Class
	 * 
	 * @param clazz
	 * @param index
	 *            第几个参数, 从0开始
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> Class<T> getSuperClassGenricType(Class<?> clazz, int index) {
		Type genType = clazz.getGenericSuperclass();
		// 如果不是ParameterizedType接口的子类 就不可能含有泛型参数
		if (!(genType instanceof ParameterizedType))
			return null;
		// 泛型信息
		Type[] params = ((ParameterizedType) genType).getActualTypeArguments();
		// 索引错误
		if (index >= params.length || index < 0)
			return null;
		// 不是class类型
		if (!(params[index] instanceof Class))
			return null;

		Class<T> result = (Class<T>) params[index];

		return result;
	}

	/**
	 * 构造List对象 如果传入的是参数仅仅为一个对象数组(Object[])或原生数组(int[], long[]等)
	 * 那么表现结果表现是不同的，Object[]为[obj[0], obj[1], obj[2]] 而原生数组则为[[int[0],
	 * int[1]，int[2]]] 多了一层嵌套，需要对原生数组进行特殊处理。
	 * 
	 * @param <T>
	 * @param ts
	 * @return
	 */
	@SafeVarargs
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public static <T> List<T> ofList(T... ts) {
		List result = new ArrayList();
		// 对Null进行特殊处理
		if (ts == null) {
			result.add(null);
			return result;
		}
		// 对单独的原始数组类型进行特殊处理
		if (ts.length == 1 && ts[0] != null && OFLIST_ARRAY_CLASS.contains(ts[0].getClass())) {
			if (ts[0] instanceof int[]) {
				int[] val = (int[]) ts[0];
				for (int v : val) {
					result.add(v);
				}
			} else if (ts[0] instanceof long[]) {
				long[] val = (long[]) ts[0];
				for (long v : val) {
					result.add(v);
				}
			} else if (ts[0] instanceof boolean[]) {
				boolean[] val = (boolean[]) ts[0];
				for (boolean v : val) {
					result.add(v);
				}
			} else if (ts[0] instanceof byte[]) {
				byte[] val = (byte[]) ts[0];
				for (byte v : val) {
					result.add(v);
				}
			} else if (ts[0] instanceof double[]) {
				double[] val = (double[]) ts[0];
				for (double v : val) {
					result.add(v);
				}
			}
		} else { // 对象数组
			for (T t : ts) {
				result.add(t);
			}
		}
		return result;
	}

	// 专供ofList类使用 对于数组类型进行特殊处理
	private static final List<?> OFLIST_ARRAY_CLASS = Utils.ofList(int[].class, long[].class, boolean[].class, byte[].class, double[].class);

	/**
	 * 构造Map对象
	 * 
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <K, V> Map<K, V> ofMap(Object... params) {
		LinkedHashMap<K, V> result = new LinkedHashMap<K, V>();
		// 无参 返回空即可
		if (params == null || params.length == 0) {
			return result;
		}
		// 处理成对参数
		int len = params.length;
		for (int i = 0; i < len; i += 2) {
			K key = (K) params[i];
			V val = (V) params[i + 1];
			result.put(key, val);
		}
		return result;
	}

	/**
	 * 基于参数创建字符串 #0开始
	 * 
	 * @param str
	 * @param params
	 * @return
	 */
	public static String createStr(String str, Object... params) {
		return ParameterizedMessage.format(str, params);
	}

	public static void intToBytes(byte[] b, int offset, int v) {
		for (int i = 0; i < 4; ++i) {
			b[offset + i] = (byte) (v >>> (24 - i * 8));
		}
	}

	public static int bytesToInt(byte[] b, int offset) {
		int num = 0;
		for (int i = offset; i < offset + 4; ++i) {
			num <<= 8;
			num |= (b[i] & 0xff);
		}
		return num;
	}

	public static int bytesToInt(Object[] b, int offset) {
		int num = 0;
		for (int i = offset; i < offset + 4; ++i) {
			num <<= 8;
			num |= (((byte) b[i]) & 0xff);
		}
		return num;
	}

	public static int bytesToLittleEndian32(byte[] b, int offset) {
		return (((int) b[offset] & 0xff)) | (((int) b[offset + 1] & 0xff) << 8) | (((int) b[offset + 2] & 0xff) << 16) | (((int) b[offset + 3] & 0xff) << 24);
	}

	public static void LittleEndian32ToBytes(byte[] b, int offset, int value) {
		b[offset + 0] = (byte) ((value) & 0xFF);
		b[offset + 1] = (byte) ((value >> 8) & 0xFF);
		b[offset + 2] = (byte) ((value >> 16) & 0xFF);
		b[offset + 3] = (byte) ((value >> 24) & 0xFF);
	}

	public static String toHexString(byte[] byteBuffer, int length) {
		StringBuffer outputBuf = new StringBuffer(length * 4);
		for (int i = 0; i < length; i++) {
			String hexVal = Integer.toHexString(byteBuffer[i] & 0xff);
			if (hexVal.length() == 1) {
				hexVal = "0" + hexVal; //$NON-NLS-1$
			}
			outputBuf.append(hexVal); // $NON-NLS-1$
		}
		return outputBuf.toString();
	}

	public static String getClassPath() {
		return Class.class.getResource("/").getPath();
	}

	/**
	 * String转为int型 如果出错 则为0
	 * 
	 * @param value
	 * @return
	 */
	public static int intValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value))
			return Double.valueOf(value).intValue();
		else
			return 0;
	}

	public static int intValue(Integer value) {
		if (null == value)
			return 0;
		else
			return value;
	}

	/**
	 * String转为long型 如果出错 则为0
	 * 
	 * @param value
	 * @return
	 */
	public static long longValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value))
			return Long.valueOf(value);
		else
			return 0;
	}

	public static long longValue(Long value) {
		return null != value ? value : 0L;
	}

	/**
	 * String转为double型 如果出错 则为0.0
	 * 
	 * @param value
	 * @return
	 */
	public static double doubleValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value))
			return Double.valueOf(value);
		else
			return 0.0D;
	}

	public static double doubleValue(Double value) {
		if (null == value)
			return 0.0D;
		else
			return value;
	}

	/**
	 * String转为float型 如果出错 则为0.0
	 * 
	 * @param value
	 * @return
	 */
	public static float floatValue(String value) {
		if (StringUtils.isNotEmpty(value) && NumberUtils.isNumber(value))
			return Float.valueOf(value);
		else
			return 0.0f;
	}

	public static float floatValue(Float value) {
		if (null == value)
			return 0.0f;
		else
			return value;
	}

	/**
	 * String转为boolean型 如果出错 则为false
	 * 
	 * @param value
	 * @return
	 */
	public static boolean booleanValue(String value) {
		if ("true".equalsIgnoreCase(value) && value != null)
			return true;
		else
			return false;
	}

	/**
	 * 读取配置文件
	 * 
	 * @return
	 */
	public static Properties readProperties(String name) {
		String filePath = Utils.class.getClassLoader().getResource(name).getPath();
		try (FileInputStream in = new FileInputStream(filePath)) {
			Properties p = new Properties();
			p.load(in);
			return p;
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 获取对象的属性 会先尝试利用getter方法获取 然后再直接访问字段属性 如果给定的属性不存在 会返回null
	 * 
	 * @param obj
	 * @param fieldName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fieldRead(Object obj, String fieldName) {
		try {
			// 返回值
			Object result = null;
			Class<? extends Object> clazz = obj.getClass();
			// 先通过自省来获取字段的值(getter方法)
			boolean hasGetter = false;
			BeanInfo bi = Introspector.getBeanInfo(clazz);
			PropertyDescriptor[] pds = bi.getPropertyDescriptors();
			for (PropertyDescriptor p : pds) {
				if (!p.getName().equals(fieldName))
					continue;
				result = p.getReadMethod().invoke(obj);
				hasGetter = true;
			}
			// 如果通过getter方法没找到 那么就尝试直接读取字段
			if (!hasGetter) {
				for (Field f : clazz.getFields()) {
					if (!f.getName().equals(fieldName))
						continue;
					result = f.get(obj);
				}
			}
			return (T) result;
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 获取对象的静态属性
	 * 
	 * @param clazz
	 * @param fieldName
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T fieldRead(Class<?> clazz, String fieldName) {
		try {
			Field field = FieldUtils.getDeclaredField(clazz, fieldName);
			return (T) field.get(clazz);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 设置对象的属性 会先尝试利用setter方法修改 然后再直接修改字段属性 如果给定的属性不存在 会抛出异常
	 * 
	 * @param obj
	 * @param fieldName
	 * @return
	 */
	public static void fieldWrite(Object obj, String fieldName, Object valueNew) {
		try {
			Class<? extends Object> clazz = obj.getClass();
			// 先通过自省来设置字段的值(setter方法)
			boolean hasSetter = false;
			BeanInfo bi = Introspector.getBeanInfo(clazz);
			PropertyDescriptor[] pds = bi.getPropertyDescriptors();
			for (PropertyDescriptor p : pds) {
				if (!p.getName().equals(fieldName))
					continue;
				// 到这里的话 证明属性能找到（至少有对应的getter）但是没有找到setter
				// 可能是setter方法不符合规范 比如非void有返回值等
				// 这种情况使用反射再次尝试
				Method wm = p.getWriteMethod();
				if (wm == null) {
					String wmStr = "set" + StringUtils.capitalize(fieldName);
					for (Method m : clazz.getMethods()) {
						if (!m.getName().equals(wmStr))
							continue;
						m.invoke(obj, valueNew);
					}
				} else {
					wm.invoke(obj, valueNew);
				}
				hasSetter = true;
			}
			// 如果通过setter方法没找到 那么就尝试直接操作字段
			if (!hasSetter) {
				Field f = clazz.getField(fieldName);
				f.set(obj, valueNew);
			}
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 通过反射执行函数
	 * 
	 * @param obj
	 * @param method
	 */
	@SuppressWarnings("unchecked")
	public static <T> T invokeMethod(Object obj, String method, Object... params) {
		try {
			return (T) MethodUtils.invokeMethod(obj, method, params);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 通过反射执行函数
	 * 
	 * @param method
	 */
	@SuppressWarnings("unchecked")
	public static <T> T invokeStaticMethod(Class<?> cls, String method, Object... params) {
		try {
			return (T) MethodUtils.invokeStaticMethod(cls, method, params);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 通过反射执行构造函数
	 * 
	 * @param cls
	 * @param params
	 * @return
	 */
	@SuppressWarnings("unchecked")
	public static <T> T invokeConstructor(Class<?> cls, Object... params) {
		try {
			return (T) ConstructorUtils.invokeConstructor(cls, params);
		} catch (Exception e) {
			throw new SysException(e);
		}
	}

	/**
	 * 进行Get请求操作
	 * 
	 * @return
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String httpGet(String url, Map<String, Object> params) throws IOException {
		// 默认参数
		if (params == null)
			params = new HashMap<>();
		// 1.1 拼接参数
		StringBuilder urlSB = new StringBuilder();
		for (Entry<String, Object> entry : params.entrySet()) {
			Object value = entry.getValue();
			String v = (value == null) ? "" : URLEncoder.encode(entry.getValue().toString(), "UTF-8");
			urlSB.append(entry.getKey()).append("=").append(v).append("&");
		}
		// 1.2 最终地址
		String urlStrFinal = params.isEmpty() ? url : url + "?" + urlSB.deleteCharAt(urlSB.length() - 1);
		// 1.3 请求地址
		HttpGet get = new HttpGet(urlStrFinal);
		// 设置超时时间为3s
		RequestConfig config = RequestConfig.custom().setSocketTimeout(60000).setAuthenticationEnabled(false).setConnectTimeout(60000).build();
		get.setConfig(config);
		// 准备环境
		try (CloseableHttpClient http = HttpClients.createDefault(); CloseableHttpResponse response = http.execute(get);) {
			// 返回内容
			HttpEntity entity = response.getEntity();
			// 主体数据
			InputStream in = entity.getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
			// 读取
			StringBuilder sb = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
			return sb.toString();
		}
	}

	public static String httpPostJson(String url, String content) throws IOException {
		if (null == url || url.isEmpty() || null == content || content.isEmpty()) {
			return "";
		}

		// 请求地址
		HttpPost httpPost = new HttpPost(url);
		httpPost.addHeader(HTTP.CONTENT_TYPE, "application/json");
		// 设置超时时间为3s
		RequestConfig config = RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000).setAuthenticationEnabled(false).build();
		httpPost.setConfig(config);
		// 设置参数
		StringEntity se = new StringEntity(content);
		se.setContentType("text/json");
		se.setContentEncoding(new BasicHeader(HTTP.CONTENT_TYPE, "application/json"));
		httpPost.setEntity(se);
		// 准备环境
		try (CloseableHttpClient http = HttpClients.createDefault(); CloseableHttpResponse response = http.execute(httpPost);) {
			// 返回内容
			HttpEntity entity = response.getEntity();
			// 主体数据
			InputStream in = entity.getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
			// 读取
			StringBuilder sb = new StringBuilder();
			String line = null;
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
			return sb.toString();
		}
	}

	/**
	 * 进行Post请求操作
	 * 
	 * @return
	 * @throws IOException
	 * @throws ClientProtocolException
	 */
	public static String httpPost(String url, Map<String, Object> params) throws IOException {
		// 默认参数
		if (params == null)
			params = new HashMap<>();
		// 参数
		List<NameValuePair> nvps = new ArrayList<>();
		for (Entry<String, Object> entry : params.entrySet()) {
			String key = entry.getKey();
			Object val = entry.getValue();
			String valStr = (val == null) ? "" : val.toString();
			nvps.add(new BasicNameValuePair(key, valStr));
		}
		// 请求地址
		HttpPost post = new HttpPost(url);
		// 设置超时时间为3s
		RequestConfig config = RequestConfig.custom().setSocketTimeout(3000).setConnectTimeout(3000).setAuthenticationEnabled(false).build();
		post.setConfig(config);
		// 设置参数
		post.setEntity(new UrlEncodedFormEntity(nvps, "UTF-8"));
		// 准备环境
		try (CloseableHttpClient http = HttpClients.createDefault(); CloseableHttpResponse response = http.execute(post)) {
			// 返回内容
			HttpEntity entity = response.getEntity();
			// 主体数据
			InputStream in = entity.getContent();
			BufferedReader reader = new BufferedReader(new InputStreamReader(in, "UTF-8"));
			// 读取
			StringBuilder sb = new StringBuilder();
			String line;
			while ((line = reader.readLine()) != null) {
				sb.append(line);
			}
			return sb.toString();
		}
	}

	/**
	 * 从字符串转为JSONArray，主要目的是包装一下空值处理
	 * 
	 * @param str
	 * @return 正常返回对象，否则返回长度为0的JSONArray
	 */
	public static JSONArray toJSONArray(String str) {
		if (StringUtils.isEmpty(str)) {
			str = "[]";
		}
		return JSON.parseArray(str);
	}

	/**
	 * 从字符串转为JSONObject，主要目的是包装一下空值处理
	 * 
	 * @param str
	 * @return 正常返回对象，否则返回空的JSONObject
	 */
	public static JSONObject toJSONObject(String str) {
		if (StringUtils.isEmpty(str)) {
			str = "{}";
		}
		return JSON.parseObject(str);
	}

	/**
	 * 将对象转化为JSON字符串
	 * 
	 * @param obj
	 * @return
	 */
	public static String toJSONString(Object obj) {
		return JSON.toJSONString(obj, SerializerFeature.DisableCircularReferenceDetect);
	}

	public static boolean isEmptyStr(String s) {
		return s == null || "".equals(s.trim());
	}

	public static int getIdInt(String id) {
		if (id == null) {
			return 0;
		}
		Pattern pattern = Pattern.compile("[0-9]*");
		Matcher isNum = pattern.matcher(id);
		if (!isNum.matches()) {
			return id.length();
		}
		return Integer.parseInt(id);
	}

	/**
	 * 是否为全平台全渠道全区服
	 * 
	 * @param p
	 * @param c
	 * @param s
	 * @return
	 */
	public static boolean isAllPCS(String p, String c, String s) {
		return "0".equals(p) && "0".equals(c) && "0".equals(s);
	}

	public static Map<String, String> getProjects(String url, String username, String projectname) {
		Map<String, String> result = new LinkedHashMap<>();

		Map<String, String> ower = new LinkedHashMap<>();
		Map<String, String> other = new LinkedHashMap<>();

		try {
			CloseableHttpClient httpclient = HttpClientBuilder.create().build();
			HttpGet httpgets = new HttpGet(url + "/resources/pages/rest.jsf?method=getProjects&username=" + username);
			HttpResponse res = httpclient.execute(httpgets);
			HttpEntity entity = res.getEntity();
			if (entity != null) {
				InputStream instreams = entity.getContent();
				String ps = convertStreamToString(instreams);
				httpgets.abort();

				Map<String, String> ss = toMap(ps);
				String status = ss.get("status");
				if ("1".equals(status)) {
					String addrNames = ss.get("addrNames");
					String addrUrls = ss.get("addrUrls");

					String[] names = addrNames.split(";");
					String[] urls = addrUrls.split(";");

					for (int i = 0; i < names.length; i++) {
						if (StringUtils.isNotEmpty(names[i])) {
							if (projectname != null && names[i].equals(projectname)) {
								ower.put(names[i], "bi");
							} else {
								other.put(names[i], urls[i]);
							}
						}
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return result;
		}

		if (ower.size() == 0) {
		    ower.put(projectname, "bi");
        }

		result.putAll(ower);
		result.putAll(other);

		return result;
	}

	public static Map<String, String> getProjectids(String url) {
		Map<String, String> result = new LinkedHashMap<>();
		try {
			CloseableHttpClient httpclient = HttpClientBuilder.create().build();
			HttpGet httpgets = new HttpGet(url);
			HttpResponse res = httpclient.execute(httpgets);
			HttpEntity entity = res.getEntity();
			if (entity != null) {
				String ps = EntityUtils.toString(entity , "UTF-8").trim();  
				httpgets.abort();
				Map<String, String> ss = toMap(ps);
				String status = ss.get("code");
				if ("0".equals(status)) {
					String msg = ss.get("msg");
					List<Map> m = JSONArray.parseArray(msg, Map.class);
					for(Map<String,String> a : m){
						result.put(a.get("projectName"),String.valueOf(a.get("id")));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
			return result;
		}
		return result;
	}
	
	public static Map<String, String> toMap(String jsonString) throws JSONException {
		org.json.JSONObject jsonObject = new org.json.JSONObject(jsonString);

		Map<String, String> result = new LinkedHashMap<>();
		Iterator<?> iterator = jsonObject.keys();

		while (iterator.hasNext()) {
			String key = (String) iterator.next();
			String value = jsonObject.getString(key);
			result.put(key, value);
		}
		return result;
	}

	public static String convertStreamToString(InputStream is) throws IOException {
		BufferedReader reader = new BufferedReader(new InputStreamReader(is));
		StringBuilder sb = new StringBuilder();

		String line = null;
		while ((line = reader.readLine()) != null) {
			sb.append(line + System.getProperty("line.separator"));
		}
		is.close();

		return sb.toString();
	}

	public static String matchesString(String s) {
		String buffer = s;
		if (s != null && !"".equals(s.trim())) {
			String regex = ".*?[\\u4e00-\\u9fa5].*?";
			boolean flag = s.matches(regex);
			if (!flag) {
				// 首先使用转码的方式测试
				try {
					String str = java.net.URLDecoder.decode(s, "UTF-8");
					flag = str.matches(regex);
					if (flag) {
						return str;
					}
				} catch (Exception e1) {
					e1.printStackTrace();
				}
			}

			int i = 0;
			// 处理浏览器发送的请求
			while (!flag && i < charsetArray.length) {
				try {
					String newStr = new String(s.getBytes("ISO8859-1"),
							charsetArray[i]);
					if (i == 0) {
						// 缓存第一次的请求
						buffer = newStr;
					}
					i++;
					flag = newStr.matches(regex);
					if (flag) {
						return newStr;
					}
				} catch (Exception e) {
					e.printStackTrace();
				}
			}
		}
		return buffer;
	}

	private static String[] charsetArray = new String[] { "UTF-8", "GBK",
			"GB2312" };



	// "["2","3","4"]" 转成 List("2", "3", "4")
    public static List<String> getStringList(List<String> strList) {
        List<String> result = new ArrayList<>();

        if (strList != null && strList.size() > 0) {
            String str = strList.get(0);
            if (!org.datanucleus.util.StringUtils.isEmpty(str) && str.contains("[") && str.contains("]")) {
                String[] stmp1 = str.split("\\[");
                if (stmp1 != null && stmp1.length > 1 && !org.datanucleus.util.StringUtils.isEmpty(stmp1[1])) {
                    String[] stmp2 = stmp1[1].split("]");
                    if (stmp2 != null && stmp2.length > 0 && !org.datanucleus.util.StringUtils.isEmpty(stmp2[0])) {
                        String s = stmp2[0];
                        if (!org.datanucleus.util.StringUtils.isEmpty(s)) {
                            String[] ss = s.split(",");
                            if (ss != null && ss.length > 0 && !org.datanucleus.util.StringUtils.isEmpty(ss[0])) {
                                for (String s1 : ss) {
                                    result.add(s1.trim().replaceAll("\"", ""));
                                }
                            }
                        }
                    }
                }
            }
        }

        return result;
    }

    public static void main(String[] args) throws IOException, InvalidFormatException {
        /*InputStream input = new FileInputStream("c://jj.xlsx");
        Workbook wb = WorkbookFactory.create(input);
        Sheet tempSheet = wb.getSheetAt(0);


        Workbook wb1 = new HSSFWorkbook();
        Sheet sheet1 = wb1.createSheet("mjexcel1");

        int rowNum = tempSheet.getLastRowNum();// 获得总行数
        for (int i = 0; i <= rowNum; i++) {
            Row row = tempSheet.getRow(i);

            String mac = com.loongtech.bi.support.ExcelUtils.getCellValue(row.getCell(0));
            String level = com.loongtech.bi.support.ExcelUtils.getCellValue(row.getCell(1));

            Row row1 = sheet1.createRow(i);
            Cell cell = row1.createCell(0);
            Cell cell1 = row1.createCell(1);
            Cell cell2 = row1.createCell(2);
            cell.setCellValue(mac);
            cell1.setCellValue(level);
            cell2.setCellValue(Utils.md5(mac));
        }



        FileOutputStream fileOut = new FileOutputStream("C:/mj2.csv");
        wb1.write(fileOut);
        fileOut.close();


        IOUtils.closeQuietly(input);*/

        System.out.println(Time.formatTime(1504265080000L, Time.TIMEPATTERN_ALL3));
    }

}
